package com.ruoyi.excelutils.service.impl;


import com.alibaba.excel.EasyExcel;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.excelutils.constant.ExcelFormat;
import com.ruoyi.excelutils.entity.ExcelHeaderInfo;
import com.ruoyi.excelutils.entity.po.TtlProductInfoPo;
import com.ruoyi.excelutils.entity.vo.HqNetworkBillDetailExportPageSizeVo;
import com.ruoyi.excelutils.mapper.TtlProductInfoMapper;
import com.ruoyi.excelutils.service.TtlProductInfoService;
import com.ruoyi.excelutils.utils.ExcelUtilsTest;
import com.ruoyi.hqfinance.domain.HqExportInfo;
import com.ruoyi.hqfinance.domain.HqNetworkBillDetail;
import com.ruoyi.hqfinance.domain.vo.HqNetworkBillPointVo;
import com.ruoyi.hqfinance.mapper.HqExportInfoMapper;
import com.ruoyi.statisticalCenter.domain.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author kundy
 * @create 2019/2/16 11:22 AM
 */
@Service
@Slf4j
public class TtlProductInfoServiceImpl implements TtlProductInfoService {

    // 每个线程导出记录最大行数
    private static final int THREAD_MAX_ROW = 25000;

    @Autowired
    private TtlProductInfoMapper mapper;

    @Autowired
    private HqExportInfoMapper hqExportInfoMapper;
    

    @Override
    public List<TtlProductInfoPo> listProduct(Map<String, Object> map) {
        return this.mapper.listProduct(map);
    }

    @Override
    public List<TtlProductInfoPo> list(Map<String, Object> map, HqNetworkBillDetailExportPageSizeVo vo) {
        return this.mapper.list(vo);
    }

    @Override
    public List<TtlProductInfoPo> scOutList(Map<String, Object> map, HqNetworkBillPointVo vo) {
        return this.mapper.point(vo);
    }

    @Override
    public List<TtlProductInfoPo> scPaiGrossProfitSheetList(Map<String, Object> map, ScEnterPaiGrossProfitSheetPointVo vo) {
        return this.mapper.scEnterPaiGrossProfitSheetPoint(vo);
    }

    @Override
    public List<TtlProductInfoPo> scQualityList(Map<String, Object> map, ScQualityControlFeeSheetPointVo vo) {
        return this.mapper.scQualityPoint(vo);
    }

    @Override
    public List<TtlProductInfoPo> scIncomeAndExpendList(Map<String, Object> map, ScHqIncomeAndExpendCollectPointVo vo) {
//        PageHelper.startPage(Integer.valueOf(String.valueOf(map.get("offset"))),Integer.valueOf(String.valueOf(map.get("limit"))));
        return this.mapper.hqIncomeAndExpendPoint(map,vo);
    }

    @Override
    public List<TtlProductInfoPo> scOutPortWarehouseList(Map<String, Object> map, ScOutPortWarehouseGrossProfitSheetPointVo vo) {
        return this.mapper.scOutPortWarehousePoint(vo);
    }

    @Override
    public List<TtlProductInfoPo> scWeightFlowList(Map<String, Object> map, ScWeightFlowDirectionDispositionPointVo vo) {
        if (vo.getNetworkLevel() == 0){
            return this.mapper.scWeightFlowPoint(vo);
        }else {
            return this.mapper.scWeightFlowClientPoint(vo);
        }
    }

    @Override
    public List<TtlProductInfoPo> scOutReturnList(Map<String, Object> map, ScOutReturnSheetPointVo vo) {
        return this.mapper.scOutReturnSheetPoint(vo);
    }

    @Override
    public void export(HttpServletResponse response, String fileName) {
        // 待导出数据
        List<TtlProductInfoPo> productInfoPos = this.multiThreadListProduct();
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, fileName, excelUtilsTest.getWorkbook());
    }

    @Override
    public void list(HttpServletResponse response, String s, HqNetworkBillDetailExportPageSizeVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.billMultiThreadListProduct(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scOutExport(HttpServletResponse response, String s, HqNetworkBillPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scMultiThreadListProduct(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scPaiGrossProfitSheetExport(HttpServletResponse response, String s, ScEnterPaiGrossProfitSheetPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scEnterPaiGrossProfit(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scQualityExport(HttpServletResponse response, String s, ScQualityControlFeeSheetPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scQuality(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scIncomeAndExpendExport(HttpServletResponse response, String s, ScHqIncomeAndExpendCollectPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scIncomeExpend(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scOutPortWarehouseExport(HttpServletResponse response, String s, ScOutPortWarehouseGrossProfitSheetPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scOutPortWarehouseExpend(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scWeightFlowExport(HttpServletResponse response, String s, ScWeightFlowDirectionDispositionPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scWeightFlowExpend(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    public void scOutReturnExport(HttpServletResponse response, String s, ScOutReturnSheetPointVo vo) {
        List<TtlProductInfoPo> productInfoPos = this.scOutReturnExpend(vo);
        ExcelUtilsTest excelUtilsTest = new ExcelUtilsTest(productInfoPos, getHeaderInfo(), getFormatInfo());
        excelUtilsTest.sendHttpResponse(response, s, excelUtilsTest.getWorkbook());
    }

    @Override
    @Async
    public R exportDetailAsync(ScHqIncomeAndExpendCollectPointVo vo) {

        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "总部收支汇总报表" + startTime + ".zip";
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;;
        String sheetName = "总部收支汇总报表";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> list = mapper.hqIncomeAndExpendPoint(null, vo);
        System.out.println("查询数据的耗时：" + (System.currentTimeMillis() - startTime));
        System.out.println("数据条数："+list.size());

        // 创建一个临时文件来存储Excel文件
        String tempFilePath = "/tmp/temp_excel.xlsx";
        EasyExcel.write(tempFilePath, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(list);

        // 将Excel文件添加到ZIP文件中
        try (FileInputStream fis = new FileInputStream(tempFilePath);
             FileOutputStream fos = new FileOutputStream(path);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            ZipEntry zipEntry = new ZipEntry("总部收支汇总报表.xlsx");
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 删除临时文件
        new File(tempFilePath).delete();

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scOutPortWarehouseExportAsync(ScOutPortWarehouseGrossProfitSheetPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "出港包仓毛利报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "出港包仓毛利报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scOutPortWarehouseExpend(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scOutReturnExportAsync(ScOutReturnSheetPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "出港返利毛利报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "出港返利毛利报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scOutReturnExpend(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scPaiGrossProfitSheetExportAsync(ScEnterPaiGrossProfitSheetPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "进港派件毛利报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "进港派件毛利报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scEnterPaiGrossProfit(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scWeightFlowExportAsync(ScWeightFlowDirectionDispositionPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "流向均重监控报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "流向均重监控报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scWeightFlowExpend(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scQualityExportAsync(ScQualityControlFeeSheetPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "质控费用汇总报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "质控费用汇总报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scQuality(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    @Override
    @Async
    public R scOutExportAsync(HqNetworkBillPointVo vo) {
        // 获取代码执行前的时间戳
        long startTime = System.currentTimeMillis();
        // 使用 UUID 生成唯一文件名
        String fileName = "出港发件成本报表明细_" + startTime + ".xlsx";
        //String path = "D:\\ruoyi\\uploadPath\\download\\" + fileName;
        String path = "/home/ruoyi/uploadPath/download/" + fileName;
        String sheetName = "出港发件成本报表明细";
        HqExportInfo hqExportInfo = new HqExportInfo();
        hqExportInfo.setSheetName(fileName);
        hqExportInfo.setType("下载中");
//    hqExportInfo.setCreateBy(SecurityUtils.getUserId());
        hqExportInfoMapper.insert(hqExportInfo);

        List<TtlProductInfoPo> lise = this.scMultiThreadListProduct(vo);
        System.out.println("查询数据的耗时:" + (System.currentTimeMillis() - startTime));

        // 写入 Excel 文件到临时目录
        EasyExcel.write(path, TtlProductInfoPo.class)
                .sheet(sheetName)
                .doWrite(lise);

        // 获取代码执行后的时间戳
        long endTime = System.currentTimeMillis();
        // 计算代码执行所需的毫秒数
        long executionTime = endTime - startTime;
        System.out.println("执行这段代码的耗时(毫秒)：" + executionTime);

        hqExportInfo.setType("已完成");
        hqExportInfo.setUrl(path);
        hqExportInfo.setId(hqExportInfoMapper.selectIdByName(hqExportInfo.getSheetName()));
        hqExportInfoMapper.update(hqExportInfo);

        // 返回文件信息给前端
        Map<String, Object> result = new HashMap<>();
        result.put("fileUrl", path);
        result.put("fileName", fileName);
        return R.ok(result);
    }

    // 获取表头信息
    private List<ExcelHeaderInfo> getHeaderInfo() {
        return Arrays.asList(
//                new ExcelHeaderInfo(0, 0, 0, 0, "id"),
                new ExcelHeaderInfo(0, 0, 0, 0, "运单号"),

                new ExcelHeaderInfo(0, 0, 1, 1, "大包号"),
                new ExcelHeaderInfo(0, 0, 2, 2, "结算网点编码"),
                new ExcelHeaderInfo(0, 0, 3, 3, "结算网点名称"),

                new ExcelHeaderInfo(0, 0, 4, 4, "承包区编码"),
                new ExcelHeaderInfo(0, 0, 5, 5, "承包区名称"),
                new ExcelHeaderInfo(0, 0, 6, 6, "费用名称编码"),

                new ExcelHeaderInfo(0, 0, 7, 7, "费用名称"),
                new ExcelHeaderInfo(0, 0, 8, 8, "结算科目名称编码"),
                new ExcelHeaderInfo(0, 0, 9, 9, "结算科目名称"),

                new ExcelHeaderInfo(0, 0, 10, 10, "费用子项名称编码"),
                new ExcelHeaderInfo(0, 0, 11, 11, "费用子项名称"),
                new ExcelHeaderInfo(0, 0, 12, 12, "收入"),
                new ExcelHeaderInfo(0, 0, 13, 13, "支出"),
                new ExcelHeaderInfo(0, 0, 14, 14, "进/出港"),
                new ExcelHeaderInfo(0, 0, 15, 15, "结算重量"),
                new ExcelHeaderInfo(0, 0, 16, 16, "费用说明"),
                new ExcelHeaderInfo(0, 0, 17, 17, "寄件日期"),
                new ExcelHeaderInfo(0, 0, 18, 18, "会计日期"),
                new ExcelHeaderInfo(0, 0, 19, 19, "扣付日期"),
                new ExcelHeaderInfo(0, 0, 20, 20, "费用大类名称编码"),
                new ExcelHeaderInfo(0, 0, 21, 21, "费用大类名称"),
                new ExcelHeaderInfo(0, 0, 22, 22, "费用小类名称编码"),
                new ExcelHeaderInfo(0, 0, 23, 23, "费用小类名称"),
                new ExcelHeaderInfo(0, 0, 24, 24, "网点称重"),
                new ExcelHeaderInfo(0, 0, 25, 25, "直属称重"),
                new ExcelHeaderInfo(0, 0, 26, 26, "第三方称重"),
                new ExcelHeaderInfo(0, 0, 27, 27, "计泡重"),
                new ExcelHeaderInfo(0, 0, 28, 28, "长*宽*高"),
                new ExcelHeaderInfo(0, 0, 29, 29, "运输方式"),
                new ExcelHeaderInfo(0, 0, 30, 30, "转运中心名称"),
                new ExcelHeaderInfo(0, 0, 31, 31, "始发承包区名称"),
                new ExcelHeaderInfo(0, 0, 32, 32, "始发上级网点名称"),
                new ExcelHeaderInfo(0, 0, 33, 33, "收件承包区名称"),
                new ExcelHeaderInfo(0, 0, 34, 34, "收件上级网点名称"),
                new ExcelHeaderInfo(0, 0, 35, 35, "揽件员名称"),
                new ExcelHeaderInfo(0, 0, 36, 36, "始发城市名称"),
                new ExcelHeaderInfo(0, 0, 37, 37, "目的承包区名称"),
                new ExcelHeaderInfo(0, 0, 38, 38, "目的上级网点名称"),
                new ExcelHeaderInfo(0, 0, 39, 39, "派件员名称"),
                new ExcelHeaderInfo(0, 0, 40, 40, "目的省份名称"),
                new ExcelHeaderInfo(0, 0, 41, 41, "目的省份编码"),
                new ExcelHeaderInfo(0, 0, 42, 42, "目的城市名称"),
                new ExcelHeaderInfo(0, 0, 43, 43, "目的城市编码"),
                new ExcelHeaderInfo(0, 0, 44, 44, "客户名称"),
                new ExcelHeaderInfo(0, 0, 45, 45, "订单来源")
        );
    }

    // 获取格式化信息
    private Map<String, ExcelFormat> getFormatInfo() {
        Map<String, ExcelFormat> format = new HashMap<>();
        format.put("transportCode", ExcelFormat.FORMAT_STRING);
        format.put("bagCode", ExcelFormat.FORMAT_STRING);
        format.put("settleNetworkNameId", ExcelFormat.FORMAT_STRING);
        format.put("settleNetworkName", ExcelFormat.FORMAT_STRING);
        format.put("contractAreaId", ExcelFormat.FORMAT_STRING);
        format.put("contractArea", ExcelFormat.FORMAT_STRING);
        format.put("hqCostKindId", ExcelFormat.FORMAT_STRING);
        format.put("hqCostKind", ExcelFormat.FORMAT_STRING);
        format.put("hqSettleObjectId", ExcelFormat.FORMAT_STRING);
        format.put("hqSettleObject", ExcelFormat.FORMAT_STRING);
        format.put("hqCostSubitemId", ExcelFormat.FORMAT_STRING);
        format.put("hqCostSubitem", ExcelFormat.FORMAT_STRING);
        format.put("income", ExcelFormat.FORMAT_DOUBLE);
        format.put("expend", ExcelFormat.FORMAT_DOUBLE);
        format.put("boundType", ExcelFormat.FORMAT_STRING);
        format.put("settleWeight", ExcelFormat.FORMAT_STRING);
        format.put("costExplain", ExcelFormat.FORMAT_STRING);
        format.put("sendDate", ExcelFormat.FORMAT_STRING);
        format.put("accountantDate", ExcelFormat.FORMAT_STRING);
        format.put("deductPayDate", ExcelFormat.FORMAT_STRING);
        format.put("costBigKindId", ExcelFormat.FORMAT_STRING);
        format.put("costBigKind", ExcelFormat.FORMAT_STRING);
        format.put("costSmallKindId", ExcelFormat.FORMAT_STRING);
        format.put("costSmallKind", ExcelFormat.FORMAT_STRING);
        format.put("networkWeight", ExcelFormat.FORMAT_STRING);
        format.put("directlyWeight", ExcelFormat.FORMAT_STRING);
        format.put("thirdPartyWeight", ExcelFormat.FORMAT_STRING);
        format.put("bubbleWeight", ExcelFormat.FORMAT_STRING);
        format.put("lengthWidthHeight", ExcelFormat.FORMAT_STRING);
        format.put("transportType", ExcelFormat.FORMAT_STRING);
        format.put("transportCentreName", ExcelFormat.FORMAT_STRING);
        format.put("startContractAreaName", ExcelFormat.FORMAT_STRING);
        format.put("startSuperiorsNetworkName", ExcelFormat.FORMAT_STRING);
        format.put("pickUpContractAreaName", ExcelFormat.FORMAT_STRING);
        format.put("pickUpSuperiorsNetworkName", ExcelFormat.FORMAT_STRING);
        format.put("solicitor", ExcelFormat.FORMAT_STRING);
        format.put("startCity", ExcelFormat.FORMAT_STRING);
        format.put("objectiveContractAreaName", ExcelFormat.FORMAT_STRING);
        format.put("objectiveSuperiorsNetworkName", ExcelFormat.FORMAT_STRING);
        format.put("courier", ExcelFormat.FORMAT_STRING);
        format.put("courierProvince", ExcelFormat.FORMAT_STRING);
        format.put("courierProvinceCode", ExcelFormat.FORMAT_STRING);
        format.put("courierCity", ExcelFormat.FORMAT_STRING);
        format.put("courierCityCode", ExcelFormat.FORMAT_STRING);
        format.put("client", ExcelFormat.FORMAT_STRING);
        format.put("orderSource", ExcelFormat.FORMAT_STRING);
        return format;
    }

    // 多线程查询报表
    private List<TtlProductInfoPo> multiThreadListProduct() {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        executeTask(tasks, loopNum, totalNum);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void executeTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new listThread(map));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class listThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;

        private listThread(Map<String, Object> map) {
            this.map = map;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return listProduct(map);
        }
    }

    //统计中心-出港返利
    private List<TtlProductInfoPo> scOutReturnExpend(ScOutReturnSheetPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scOutReturnExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scOutReturnExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScOutReturnSheetPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scOutReturnListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scOutReturnListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScOutReturnSheetPointVo vo;

        private scOutReturnListThread(Map<String, Object> map, ScOutReturnSheetPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scOutReturnList(map, vo);
        }
    }

    //    统计中心-流向均重监控表
    private List<TtlProductInfoPo> scWeightFlowExpend(ScWeightFlowDirectionDispositionPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scWeightFlowExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scWeightFlowExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScWeightFlowDirectionDispositionPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scWeightFlowListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scWeightFlowListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScWeightFlowDirectionDispositionPointVo vo;

        private scWeightFlowListThread(Map<String, Object> map, ScWeightFlowDirectionDispositionPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scWeightFlowList(map, vo);
        }
    }


    //    统计中心-出港包仓毛利报表
    private List<TtlProductInfoPo> scOutPortWarehouseExpend(ScOutPortWarehouseGrossProfitSheetPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scOutPortWarehouseExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scOutPortWarehouseExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScOutPortWarehouseGrossProfitSheetPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scOutPortWarehouseListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scOutPortWarehouseListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScOutPortWarehouseGrossProfitSheetPointVo vo;

        private scOutPortWarehouseListThread(Map<String, Object> map, ScOutPortWarehouseGrossProfitSheetPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scOutPortWarehouseList(map, vo);
        }
    }

    //    统计中心-总部收支汇总
    private List<TtlProductInfoPo> scIncomeExpend(ScHqIncomeAndExpendCollectPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        Integer count = mapper.hqIncomeAndExpendPointCount(vo);
        int totalNum = 5000;
        if (count!=null && count !=0){
            totalNum=count;
        }
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scIncomeExpendExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scIncomeExpendExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScHqIncomeAndExpendCollectPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scIncomeExpendListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scIncomeExpendListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScHqIncomeAndExpendCollectPointVo vo;

        private scIncomeExpendListThread(Map<String, Object> map, ScHqIncomeAndExpendCollectPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scIncomeAndExpendList(map, vo);
        }
    }


    //    统计中心-质控费用汇总报表
    private List<TtlProductInfoPo> scQuality(ScQualityControlFeeSheetPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scQualityExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scQualityExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScQualityControlFeeSheetPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scQualityListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scQualityListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScQualityControlFeeSheetPointVo vo;

        private scQualityListThread(Map<String, Object> map, ScQualityControlFeeSheetPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scQualityList(map, vo);
        }
    }


//    统计中心-进港派件毛利报表

    private List<TtlProductInfoPo> scEnterPaiGrossProfit(ScEnterPaiGrossProfitSheetPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scEnterPaiGrossProfitSheetPointVoExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scEnterPaiGrossProfitSheetPointVoExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, ScEnterPaiGrossProfitSheetPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scEnterPaiGrossProfitListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scEnterPaiGrossProfitListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private ScEnterPaiGrossProfitSheetPointVo vo;

        private scEnterPaiGrossProfitListThread(Map<String, Object> map, ScEnterPaiGrossProfitSheetPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scPaiGrossProfitSheetList(map, vo);
        }
    }


//    统计中心出港报表

    // 多线程查询报表
    private List<TtlProductInfoPo> scMultiThreadListProduct(HqNetworkBillPointVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 5000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        scExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void scExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, HqNetworkBillPointVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new scListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class scListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private HqNetworkBillPointVo vo;

        private scListThread(Map<String, Object> map, HqNetworkBillPointVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return scOutList(map, vo);
        }
    }


    //    网点明细
// 多线程查询报表
    private List<TtlProductInfoPo> billMultiThreadListProduct(HqNetworkBillDetailExportPageSizeVo vo) {
        List<FutureTask<List<TtlProductInfoPo>>> tasks = new ArrayList<>();
        List<TtlProductInfoPo> productInfoPos = new ArrayList<>();

        int totalNum = 25000;
        int loopNum = new Double(Math.ceil((double) totalNum / THREAD_MAX_ROW)).intValue();
        log.info("多线程查询，总数：{},开启线程数：{}", totalNum, loopNum);
        long start = System.currentTimeMillis();

        billExecuteTask(tasks, loopNum, totalNum, vo);

        for (FutureTask<List<TtlProductInfoPo>> task : tasks) {
            try {
                productInfoPos.addAll(task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        log.info("查询结束，耗时:{}", System.currentTimeMillis() - start);
        return productInfoPos;
    }

    // 执行查询任务
    private void billExecuteTask(List<FutureTask<List<TtlProductInfoPo>>> tasks, int loopNum, int total, HqNetworkBillDetailExportPageSizeVo vo) {
        for (int i = 0; i < loopNum; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("offset", i * THREAD_MAX_ROW);
            if (i == loopNum - 1) {
                map.put("limit", total - THREAD_MAX_ROW * i);
            } else {
                map.put("limit", THREAD_MAX_ROW);
            }
            FutureTask<List<TtlProductInfoPo>> task = new FutureTask<>(new billListThread(map, vo));
            log.info("开始查询第{}条开始的{}条记录", i * THREAD_MAX_ROW, THREAD_MAX_ROW);
            new Thread(task).start();
            // 将任务添加到tasks列表中
            tasks.add(task);
        }
    }

    private class billListThread implements Callable<List<TtlProductInfoPo>> {

        private Map<String, Object> map;
        private HqNetworkBillDetailExportPageSizeVo vo;

        private billListThread(Map<String, Object> map, HqNetworkBillDetailExportPageSizeVo vo) {
            this.map = map;
            this.vo = vo;
        }

        @Override
        public List<TtlProductInfoPo> call() {
            return list(map, vo);
        }
    }

}
